/*
 * @Author: your name
 * @Date: 2022-02-20 07:55:15
 * @LastEditTime: 2022-03-20 21:34:19
 * @Descripttion: 描述
 */
#include "auto_display.h"
AutoDisplay::AutoDisplay()
{
    openPageCallback = nullptr;
}
void AutoDisplay::Display(std::shared_ptr<AutoDisplayMessage> msg, bool immediately)
{
    // auto func = [](std::shared_ptr<AutoDisplay> display, std::shared_ptr<AutoDisplayMessage> msg, bool immediately) {
    //     // display->OpenPage(msg, immediately);
    //     LOG_I("open volume page.\n");
    // };
    // auto test = [](int a, std::shared_ptr<AutoDisplay> display) { LOG_I("open volume page a = %d.\n", a); };
    std::thread t(&AutoDisplay::OpenPage, this, msg, immediately);
    t.detach(); //设置线程分离属性，线程结束后自动释放资源
}
static void OpenAutoDisplayPageIQ(void* ctx)
{
    IS_VALID_PTR(ctx)
    // Context* p = (Context*)ctx;
    ContextV2<std::shared_ptr<AutoDisplay>>* p = (ContextV2<std::shared_ptr<AutoDisplay>>*)ctx;
    PageHandle* window = new PageHandle;
    if (!window->PageOpen(p->data->mPageName.c_str())) {
        LOG_E("window open error\n");
        delete window;
        delete p;
        return;
    }
    /**
     * @brief
     * TODO: 避免界面空洞未优化。
     */
    // TipsMsg tips;
    // if (DisplayTips::GetInstance().GetOneTips(tips)) {
    //     DisplayTips::GetInstance().AddTips(tips);
    //     Context* p2 = new Context;
    //     window->SaveContext(p2);
    //     /**
    //      * @brief
    //      * ctx 将会异步释放
    //      */
    //     TipsMsg* ctx = new TipsMsg;
    //     *ctx = tips;
    //     p2->ctx = ctx;
    //     DisplayTips::GetInstance().TipsDisplayingSetText(p2);
    // }
    p->data->SetPage(window);
    delete p;
}
// static void DisplayingThread(std::shared_ptr<AutoDisplay> display)
// {
//     display->Displaying();
// }
void AutoDisplay::OpenPage(std::shared_ptr<AutoDisplayMessage> msg, bool immediately)
{
    /**
     * @brief
     * TODO: 基类不要用static
     */
    static std::mutex lock;
    std::unique_lock<std::mutex> mtx_lock(lock, std::defer_lock);
    if (mtx_lock.try_lock() == true) {
        AddMessage(msg);
        keepWorking = true;
        /**
         * @brief
         * p指针在callback释放
         */
        ContextV2<std::shared_ptr<AutoDisplay>>* p = new ContextV2<std::shared_ptr<AutoDisplay>>(shared_from_this());
        p->eventCallback = OpenAutoDisplayPageIQ;
        if (!GuiEngine::GetInstance().IdleQueue(p)) {
            LOG_W("IdleQueue_V2 falied\n");
            delete p;
        }
        std::thread t(&AutoDisplay::Displaying, this);
        t.join();
        StopDisplay();
        mtx_lock.unlock();
    } else {
        if (immediately) {
            TipsDisplayingRightNow(msg);
        } else {
            AddMessage(msg);
        }
        LOG_I("volume page has been opened\n");
    }
}
void AutoDisplay::AddMessage(std::shared_ptr<AutoDisplayMessage> msg)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    mMessageQueue.push_back(msg);
}
bool AutoDisplay::GetOneMessage(std::shared_ptr<AutoDisplayMessage>& msg)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    if (mMessageQueue.size() == 0) {
        return false;
    }
    msg = mMessageQueue.front();
    mMessageQueue.pop_front();
    return true;
}
bool AutoDisplay::GetOneMessageWithoutDelete(std::shared_ptr<AutoDisplayMessage>& msg)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    if (mMessageQueue.size() == 0) {
        return false;
    }
    msg = mMessageQueue.front();
    return true;
}
PageHandle* AutoDisplay::GetPage()
{
    std::lock_guard<std::mutex> locker(m_mutex);
    return page.get();
}
void AutoDisplay::SetPage(PageHandle* window)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    page.reset(window);
}
static void DisplayingOneMessageIQ(void* ctx)
{
    IS_VALID_PTR(ctx)
    std::shared_ptr<AutoDisplayMessage> msg;
    ContextV2<std::shared_ptr<AutoDisplay>>* p = (ContextV2<std::shared_ptr<AutoDisplay>>*)ctx;
    p->data->GetOneMessage(msg);
    p->data->DisplayOneMessage(msg);
    delete p;
}
void AutoDisplay::Displaying()
{
    std::shared_ptr<AutoDisplayMessage> msg;
    unsigned int SLEEP = 300;
    while (keepWorking) {
        if (!GetPage()) {
            LOG_W("display tips page isn't opened,waiting...\n");
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            continue;
        }
        if (GetOneMessageWithoutDelete(msg)) {
            /**
             * @brief
             * P指针在callback释放。
             */
            ContextV2<std::shared_ptr<AutoDisplay>>* p = new ContextV2<std::shared_ptr<AutoDisplay>>(shared_from_this());
            p->eventCallback = DisplayingOneMessageIQ;
            keepTime = msg->keepTime;
            if (!GuiEngine::GetInstance().IdleQueue(p)) {
                LOG_W("IdleQueue_V2 falied\n");
                delete p;
            }
            sleepTime = 0;
            while (keepWorking) {
                std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP));
                sleepTime += SLEEP;
                if (sleepTime >= keepTime) {
                    break;
                }
            }
        } else {
            break;
        }
    }
}
static void StopDisplayingIQ(void* ctx)
{
    IS_VALID_PTR(ctx)
    ContextV2<std::shared_ptr<AutoDisplay>>* p = (ContextV2<std::shared_ptr<AutoDisplay>>*)ctx;
    p->data->StopDisplayingClosePage();
    delete p;
}
void AutoDisplay::StopDisplay()
{
    /**
     * @brief
     * P指针在callback释放。
     */
    ContextV2<std::shared_ptr<AutoDisplay>>* p = new ContextV2<std::shared_ptr<AutoDisplay>>(shared_from_this());
    p->eventCallback = StopDisplayingIQ;
    if (!GuiEngine::GetInstance().IdleQueue(p)) {
        LOG_W("IdleQueue_V2 falied\n");
        delete p;
        return;
    }
}
void AutoDisplay::StopDisplayingClosePage()
{
    page.get()->PageClose();
}
class AutoDisplayCtx : public Context {
public:
    AutoDisplayCtx(std::shared_ptr<AutoDisplayMessage> msg, std::shared_ptr<AutoDisplay> display)
        : mMsg(msg)
        , mDisplay(display)
    {
    }
    std::shared_ptr<AutoDisplayMessage> mMsg;
    std::shared_ptr<AutoDisplay> mDisplay;
};
static void TipsDisplayingRightNowIQ(void* ctx)
{
    IS_VALID_PTR(ctx)
    AutoDisplayCtx* p = (AutoDisplayCtx*)ctx;
    p->mDisplay->DisplayOneMessage(p->mMsg);
    delete p;
}
void AutoDisplay::TipsDisplayingRightNow(const std::shared_ptr<AutoDisplayMessage>& msg)
{
    /**
     * @brief
     * P指针在callback释放。
     */
    AutoDisplayCtx* p = new AutoDisplayCtx(msg, shared_from_this());
    p->eventCallback = TipsDisplayingRightNowIQ;
    sleepTime = 0;
    keepTime = msg->keepTime;
    if (!GuiEngine::GetInstance().IdleQueue(p)) {
        LOG_W("IdleQueue_V2 falied\n");
        delete p;
    }
}